<?php


namespace app\controller\admin;

use app\common\service\face\FaceDevice;
use app\common\model\CacheRefreshHandler;
use app\common\model\StudentModel;
use app\common\service\redis\PoolRedis;
use app\model\AdminDormitory;
use app\model\AdminSchool;
use app\model\AdminStaff;
use app\model\AdminStaffData;
use app\model\AdminStaffIcCard;
use app\util\ExcelHandle;
use app\util\ReturnCode;
use app\util\Strs;
use app\util\Tools;
use think\exception\ValidateException;
use think\facade\Log;
use think\facade\Queue;
use think\facade\Request;
use think\Response;

/**
 * 学生列表
 */
class Student extends Base
{
    public function index(): Response {
        $limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
        $start = $this->request->get('page', 1);
        $school_id = $this->request->get('school_id', $this->userInfo['school_id']);
        $dor_id = $this->request->get('dor_id', '');
        $dor_stu_id = $this->request->get('dor_stu_id', '');
        $keywords = $this->request->get('name', '');
        $student_no = $this->request->get('student_no', '');
        $phone = $this->request->get('phone', '');
        $entrance_time = $this->request->get('entrance_time', '');
        $graduate_time = $this->request->get('graduate_time', '');
        $status = $this->request->get('status', null);
        $grade = $this->request->get('grade', '');
        $class_id = $this->request->get('class_id', '');
        $sortKey = $this->request->get('sortKey', 'create_time');
        $order = $this->request->get('order', 'DESC');

        $where = [
            ['s.is_delete', '=', 0],
            ['s.type', '=', AdminStaff::STUDENT]
        ];
        $obj = (new AdminStaff())->alias('s')
            ->leftJoin(['admin_staff_ic_card' => 'ic'], 'ic.staff_id=s.id and ic.is_delete = 0')
            ->where($where);
        if ($keywords) {
            array_push($where, ['s.name', 'like', "%{$keywords}%"]);
        }
        if ($student_no) {
            array_push($where, ['s.student_no', 'like', "%{$student_no}%"]);
        }
        if ($phone) {
            array_push($where, ['s.phone', '=', $phone]);
        }
        if ($school_id > 0) {
            array_push($where, ['s.school_id', '=', $school_id]);
        }
        if ($entrance_time) {
            array_push($where, ['s.entrance_time', '=', $entrance_time]);
        }
        if ($graduate_time) {
            array_push($where, ['s.graduate_time', '=', $graduate_time]);
        }
        if (!is_null($status)) {
            array_push($where, ['s.status', '=', $status]);
        }
        if ($grade) {
            array_push($where, ['s.grade', '=', $grade]);
        }
        if ($class_id) {
            array_push($where, ['s.class_id', '=', $class_id]);
        }
        // 宿舍查询
        if ($dor_id) {
            array_push($where, ['ic.dormitory_id', '=', $dor_id]);
        }
        if ($dor_stu_id) {
            array_push($where, ['ic.student_dormitory_id', '=', $dor_stu_id]);
        }
        $listObj = $obj->where($where)
            ->with(['school', 'class', 'icCard'=>['student', 'dormitory']])
            ->field('s.id,s.school_id,s.student_no,s.name,s.sex,s.major,s.phone,s.grade,s.class_id,s.create_time,s.status,s.entrance_time,s.graduate_time,s.face,s.user_level')
            ->group('s.id')
            ->append(['status_text'])
            ->order('s.'.$sortKey, $order)
            ->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
        return $this->buildSuccess([
            'list'  => $listObj['data'],
            'count' => $listObj['total']
        ]);
    }

    public function add(): Response {
        $postData = $this->request->post();
        try {
            validate(\app\validate\AdminStaff::class)->scene('student')->check($postData);
        } catch (ValidateException $e) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $e->getError());
        }
        $where['is_delete'] = 0;
        $staff = (new AdminStaff())->where([
            'is_delete' => 0,
            'phone' => $postData['phone']
        ])->findOrEmpty();
        if (!$staff->isEmpty()) {
            return $this->buildFailed(ReturnCode::DATA_EXISTS, '手机号已被使用');
        }

        $postData['uuid'] = substr(Strs::uuid(), 1, -1);
        if (!empty($postData['face'])) {
            $fileName = $postData['uuid'].".jpg"; // 首次新增使用 uuid
            if (FaceDevice::base64_image_content($postData['face'], app()->getRootPath() . 'public/upload/faces/', $fileName)) {
                $postData['face'] = '/upload/faces/'.$fileName;
            } else {
                return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '人脸图片保存失败');
            }
        }
        if (empty($postData['password'])) {
            $postData['password'] = substr($postData['phone'], -6);
        }
        $postData['password'] = Tools::userMd5($postData['password']);
        $postData['type'] = AdminStaff::STUDENT;
        $postData['status'] = AdminStaff::AUDIT_PASS;

        $staff = AdminStaff::create($postData);
        if ($staff === false) {
            return $this->buildFailed(ReturnCode::DB_SAVE_ERROR);
        }
        if ($postData['selected_arr']) {
            try {
                FaceDevice::editPerson($staff->id);// 更新人脸设备信息
                StudentModel::lockAuthorization($postData['selected_arr'], $staff->id);
            } catch (\Exception $e) {
                return $this->buildFailed(ReturnCode::UPDATE_FAILED, $e->getMessage());
            }
        }
        return $this->buildSuccess();
    }

    // 学生管理宿舍tree数据
    public function staffStuDor(): Response {
        $staff_id = $this->request->get('id', '');
        $school_id = $this->request->get('school_id');

        $dormitory = AdminDormitory::where([
            'school_id' => $school_id,
            'is_delete' => 0
        ]);
        if ($staff_id) {
            $staff_card_query = AdminStaffIcCard::where([
                'staff_id' => $staff_id,
                'school_id' => $school_id,
                'is_delete' => 0
            ])->field('student_dormitory_id,activate_time,sim_activate_time,lock_permission')->buildSql();
            $dormitory->with([
                'student' => function ($query) use ($staff_card_query) {
                    $query->alias('sd')
                        ->leftJoin([$staff_card_query => 'card'], 'card.student_dormitory_id=sd.id')
                        ->field('card.*');
                }
            ]);
        } else {
            $dormitory->with('student');
        }

        $dormitoryList = $dormitory->select()->toArray();
        $list = [];
        foreach ($dormitoryList as $item) {
            $temp = [
                'value' => $item['id'],
                'title' => $item['name']
            ];
            if ($item['student']) {
                $temp['children'] = [];
                // $selected = false;
                foreach ($item['student'] as $student) {
                    $children = [
                        'value' => $student['id'],
                        'title' => $student['student_dormitory_name'],
                        'permission' => []
                    ];
                    if (isset($student['student_dormitory_id'])) {
                        $children['checked'] = true;
                        $children['is_card'] = $student['activate_time'] != '';
                        $children['is_sim'] = $student['sim_activate_time'] != '';
                        if ($student['lock_permission']) {
                            $children['permission'] = array_map(function ($i) {
                                return (int)$i;
                            }, explode(',', $student['lock_permission']));
                        }
                    }
                    array_push($temp['children'], $children);
                }
                array_multisort(array_column($temp['children'], 'title'), SORT_ASC, $temp['children']);
            }
            array_push($list, $temp);
        }
        return $this->buildSuccess($list);
    }

    public function edit(): Response {
        $insert = input('post.');
        $selected_arr = Request::post('selected_arr/a');
        try {
            validate(\app\validate\AdminStaff::class)->scene('student')->check($insert);
        } catch (ValidateException $e) {
            return $this->buildFailed(ReturnCode::PARAM_INVALID, $e->getError());
        }

        $student = (new AdminStaff())->where('is_delete', 0)
            ->where('id', $insert['id'])->findOrEmpty();
        if ($student->isEmpty()) {
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '账户未找到');
        }
        $staff = (new AdminStaff())->where([
            'is_delete' => 0,
            'phone' => $insert['phone']
        ])->where('id', '<>', $insert['id'])->findOrEmpty();
        if (!$staff->isEmpty()) {
            return $this->buildFailed(ReturnCode::DATA_EXISTS, '手机号已被使用');
        }

        if (empty($insert['password'])) {
            unset($insert['password']);
        } else {
            $insert['password'] = Tools::userMd5($insert['password']);
        }

        if (!empty($insert['face']) && preg_match('/^(data:\s*image\/(\w+);base64,)/', $insert['face'])) {
            $fileName = $insert['id'].".jpg";
            if (FaceDevice::base64_image_content($insert['face'], app()->getRootPath() . 'public/upload/faces/', $fileName)) {
                $insert['face'] = '/upload/faces/'.$fileName;
            } else {
                return $this->buildFailed(ReturnCode::DB_SAVE_ERROR, '人脸图片保存失败');
            }
        }

        unset($insert['id']);
        $origin = $student->toArray();
        $student->save($insert);
        if ($selected_arr) {
            try {
                FaceDevice::editPerson($student->id);// 更新人脸设备信息
                StudentModel::lockAuthorization($selected_arr, $student->id);
            } catch (\Exception $e) {
                return $this->buildFailed(ReturnCode::UPDATE_FAILED, $e->getMessage());
            }
        }
        CacheRefreshHandler::hIncrBy($student->toArray(), $origin);

        return $this->buildSuccess();
    }

    public function del(): Response {
        $staffList = (new AdminStaff())->where('is_delete', 0)
            ->where('id', 'in', $this->request->get('id'))->select();
        if (!$staffList) {
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '账户未找到');
        }
        foreach ($staffList as $staff) {
            $staff->is_delete = 1;
            $staff->save();
            FaceDevice::delPerson($staff->school_id, $staff->id);
        }

        return $this->buildSuccess();
    }

    public function audit(): Response {
        $id = input('post.id/d');
        $status = input('post.status/d');
        $refuse_reason = input('post.refuse_reason','','htmlspecialchars');
        $staff = (new AdminStaff())->where([
            'is_delete' => 0,
            'id' => $id
        ])->find();
        if (!$staff) {
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '账户未找到');
        }
        $post['refuse_reason'] = input('post.refuse_reason','','htmlspecialchars');
        $staff->status = $status;
        $staff->refuse_reason = $refuse_reason;
        $staff->save();
        return $this->buildSuccess();
    }

    // 手机设备绑定列表
    public function deviceBindList(): Response {
        $limit = $this->request->get('size', config('apiadmin.ADMIN_LIST_DEFAULT'));
        $start = $this->request->get('page', 1);
        $school_id = $this->request->get('school_id', $this->userInfo['school_id']);
        $school_name = $this->request->get('school_name', '');
        $name = $this->request->get('name', '');
        $phone = $this->request->get('phone', '');
        $status = $this->request->get('status', null);

        $staffWhere = [
            ['is_delete', '=', 0]
        ];
        $obj = (new AdminStaffData());
        if ($school_id > 0) {
            array_push($staffWhere, ['school_id', '=', $school_id]);
        }
        if ($school_name) {
            $school_id_arr = AdminSchool::where('is_delete', 0)
                ->where('name','like', "%{$school_name}%")
                ->column('id');
            array_push($staffWhere, ['school_id', 'in', $school_id_arr]);
        }
        if ($name) {
            array_push($staffWhere, ['name', 'like', "%{$name}%"]);
        }
        if ($phone) {
            array_push($staffWhere, ['phone', '=', $phone]);
        }
        $where = [];
        if (!is_null($status)) {
            array_push($where, ['bind_device_status', '=', $status]);
        } else {
            array_push($where, ['bind_device_status', 'in', [1,2]]);
        }
        $list = $obj
            ->where($where)
            ->hasWhere('staff', $staffWhere)
            ->with(['staff', 'staff.school'])
			->append(['staff' => ['type_text']])
            ->order(['last_login_time' => 'DESC'])
            ->paginate(['page' => $start, 'list_rows' => $limit])->toArray();
        return $this->buildSuccess([
            'list'  => $list['data'],
            'count' => $list['total']
        ]);
    }

    // 解绑设备
    public function deviceUnbind(): Response {
        $id = Request::param('id');
        $data = AdminStaffData::find($id);
        if (!$data) {
            return $this->buildFailed(ReturnCode::RECORD_NOT_FOUND, '记录未找到');
        }
        $data->bind_device_status = 3;
        $data->save();
        // 清除绑定设备记录
        $redis = PoolRedis::instance();
        $redis->delete('deviceUUID:staff'.$data->staff_id);
        return $this->buildSuccess();
    }

    /**
     * @func lockAuthorization
     * @method POST
     * @param selected ['id' => [0,1,2,3]] 0.蓝牙开锁 1.临时密码 2.超级SIM卡 3.IC卡
     * @desc 学生宿舍间授权
     * @return Response
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @Time: 2021/12/30 16:23
     */
    public function lockAuthorization(): Response {
        $staff_id = Request::post('id');
        $selected = Request::post('selected/a');

        try {
            StudentModel::lockAuthorization($selected, $staff_id);
        } catch (\Exception $e) {
            return $this->buildFailed(ReturnCode::UPDATE_FAILED, $e->getMessage());
        }
        return $this->buildSuccess();
    }

    /**
     * @func import
     * @desc 导入职工信息
     * @return \think\Response
     * @Time: 2021/12/17 11:18
     */
    public function upload(): Response  {
        // 获取表单上传文件 例如上传了001.jpg
        $file = request()->file('excel_file');
        $school_id = request()->post('school_id');
        // 上传到本地服务器
        try {
            validate(['image'=>'fileSize:20480|fileExt:xls,xlsx'])
                ->check([$file]);
            $fileExtendName = substr(strrchr($file->getOriginalName(), '.'), 1);
            $filePath = $file->getPathname();
            if (is_file($filePath)){
                $cols = [['1' => 'number'],['2' =>'student_no'],['3' => 'phone'],['4' => 'name'],['5' => 'major'],['6' => 'id_card'],['7' => 'sex'], ['8' => 'entrance_time'], ['9' => 'graduate_time'], ['10' => 'student_dormitory_id'],['11' => 'sim_card'],['12' => 'ic_card'], ['13' => 'blue_booth_rule'], ['14' => 'temp_pwd_rule'], ['15' => 'super_sim_rule'], ['16' => 'ic_card_rule']];
                $data = ExcelHandle::importExcel($filePath,$cols,$fileExtendName,3);

                $redis = PoolRedis::instance();
                $redis->multi(\Redis::PIPELINE);

                foreach ($data as $key => $datum) {
                    $datum['type'] = AdminStaff::STUDENT;
                    $datum['school_id'] = $school_id;
                    $datum['student_no'] = trim($datum['student_no']);
                    $datum['phone'] = trim($datum['phone']);
                    $datum['major'] = trim($datum['major']);
                    $datum['id_card'] = trim($datum['id_card']);
                    $datum['smart_card'] = trim($datum['ic_card']);
                    $datum['sim_card'] = trim($datum['sim_card']);
                    $redis->lPush("upload_student", serialize($datum));
                }
                $redis->exec();
                Queue::push('app\task\job\UploadSyncHandlerJob@fire', [
                    'model'=> AdminStaff::class,
                    'action' => 'upload_student'
                ]);
            }
            return $this->buildSuccess();
        } catch (\think\exception\ValidateException $e) {
            return $this->buildFailed(ReturnCode::FILE_SAVE_ERROR, $e->getMessage());
        }
    }
    /**
     * @func download
     * @desc 导出文件
     * @return \think\Response
     * @Time: 2021/12/17 11:18
     */
    public function download(): Response  {
        $titles = [['id' => '序号'],['school_name' => '学校名称'],['dormitory_name'=>'宿舍楼'],['student_dormitory_name'=>'宿舍号'],
            ['student_no'=>'学号'],['name'=>'姓名'],['id_card'=>'身份证号'],['sex' => '性别'],['phone' => '手机号码'],['grade' => '年级'],['class_name' => '班级'],
            ['entrance_time' => '入学时间'],['graduate_time' => '毕业时间'],['create_time' => '创建时间'],['status_text' => '审核状态']];

        $school_id = $this->request->get('school_id');
        $dor_id = $this->request->get('dor_id', '');
        $dor_stu_id = $this->request->get('dor_stu_id', '');
        $keywords = $this->request->get('name', '');
        $student_no = $this->request->get('student_no', '');
        $phone = $this->request->get('phone', '');
        $entrance_time = $this->request->get('entrance_time', '');
        $graduate_time = $this->request->get('graduate_time', '');
        $grade = $this->request->get('grade', '');
        $class_id = $this->request->get('class_id', '');

        try {
            $where = [
                ['s.is_delete', '=', 0],
                ['s.type', '=', AdminStaff::STUDENT]
            ];
            $obj = (new AdminStaff())->alias('s')
                ->leftJoin(['admin_staff_ic_card' => 'ic'], 'ic.staff_id=s.id and ic.is_delete = 0')
                ->where($where);
            if ($keywords) {
                array_push($where, ['s.name', 'like', "%{$keywords}%"]);
            }
            if ($student_no) {
                array_push($where, ['s.student_no', 'like', "%{$student_no}%"]);
            }
            if ($phone) {
                array_push($where, ['s.phone', '=', $phone]);
            }
            if ($school_id > 0) {
                array_push($where, ['s.school_id', '=', $school_id]);
            }
            if ($entrance_time) {
                array_push($where, ['s.entrance_time', '=', $entrance_time]);
            }
            if ($graduate_time) {
                array_push($where, ['s.graduate_time', '=', $graduate_time]);
            }
            if ($grade) {
                array_push($where, ['s.grade', '=', $grade]);
            }
            if ($class_id) {
                array_push($where, ['s.class_id', '=', $class_id]);
            }
            // 宿舍查询
            if ($dor_id) {
                array_push($where, ['ic.dormitory_id', '=', $dor_id]);
            }
            if ($dor_stu_id) {
                array_push($where, ['ic.student_dormitory_id', '=', $dor_stu_id]);
            }

            $listObj = $obj->where($where)->with(['school','class','icCard'=>['student', 'dormitory']])
                ->field('s.id,s.school_id,s.student_no,s.name,s.sex,s.major,s.phone,s.grade,s.class_id,s.id_card,s.create_time,s.status,s.entrance_time,s.graduate_time')
                ->group('s.id')
                ->append(['status_text'])
                ->order('s.create_time', 'DESC')
                ->select()->toArray();
            $exportData = [];
            $len = 1;
            foreach ($listObj as $datum) {
                $datum['student_no'] .= "\t";
                $datum['id_card'] .= "\t";
                $datum['phone'] .= "\t";
                $datum['entrance_time'] .= "\t";

                $dormitory_name = [];
                $student_dormitory_name = [];
                if ($datum['icCard']) {
                    foreach ($datum['icCard'] as $card) {
                        $dormitory_name[] = $card['dormitory_name'];
                        $student_dormitory_name[] = $card['student_dormitory_name'];
                    }
                }
                $datum['dormitory_name'] = join(',',array_unique($dormitory_name))."\t";
                $datum['student_dormitory_name'] = join(',',array_unique($student_dormitory_name))."\t";

                $newItem = array_merge(['id' => $len],$datum);
                array_push($exportData, $newItem);
                $len++;
            }
            ExcelHandle::downLoadExcel('学生信息' . date('YmdHi'), $titles, $exportData);

        } catch (\think\exception\ValidateException $e) {
            return $this->buildFailed(ReturnCode::FILE_SAVE_ERROR, $e->getMessage());
        }
    }

}
